package com.example.config;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.*;

/**
 * Created by IntelliJ IDEA2022.3.2
 * @Author: Tenghw
 * @Date: 2023/04/02  15:26
 * @Description: 配置线程池
 */
@Configuration
public class ThreadPoolConfig {

    /**
     * juc线程池
     * @return
     */
    @Bean(name = "asyncThreadPoolTaskExecutor")
    public Executor threadPool(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心线程数
        executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
        // 线程池维护线程的最大数量，只有在缓冲队列满了之后才会申请超过核心线程数的线程
        executor.setMaxPoolSize(100);
        // 缓存队列、任务队列容量（阻塞队列），当核心线程数达到最大时，新任务会放在队列中排队等待执行
        executor.setQueueCapacity(20);
        // 空闲时间，当超过了核心线程数之外的非核心线程,在空闲时间到达80秒之后会被销毁
        executor.setKeepAliveSeconds(80);
        // 异步方法内部线程名称
        executor.setThreadNamePrefix("tenghw-async-executor-");
        // 线程工厂
        executor.setThreadFactory(Executors.defaultThreadFactory());
        /**
         * 当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize，如果还有任务到来就会采取任务拒绝策略
         * 通常有以下4种策略：
         * ①ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
         * ②ThreadPoolExecutor.DiscardPolicy：也是丢弃任务，但是不抛出异常。
         * ③ThreadPoolExecutor.DiscardOldestPolicy：丢弃队列最前面的任务，然后重新尝试执行任务（重复此过程）
         * ④ThreadPoolExecutor.CallerRunsPolicy：重试添加当前的任务，自动重复调用 execute() 方法，直到成功
         */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }

    /**
     * com.google.guava中的线程池
     * @return
     */
    @Bean(name = "async-executor-guava")
    public Executor GuavaAsyncExecutor() {
        ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("async-executor-guava").build();
        // 当前服务器可用cpu的核数
        //最佳线程数可通过计算得出http://ifeve.com/how-to-calculate-threadpool-size/
        int corePoolSize= Runtime.getRuntime().availableProcessors() * 2;
        /**
         * int corePoolSize,
         * int maximumPoolSize,
         * long keepAliveTime,
         * TimeUnit unit,
         * BlockingQueue<Runnable> workQueue,
         * ThreadFactory threadFactory
         */
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(corePoolSize, 100,
                200, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(), threadFactory);
        //允许核心线程超时被回收，否则核心线程超时时永远不会被回收的
        threadPool.allowsCoreThreadTimeOut();
        return threadPool;
    }
}
